package com.jugheadzhou.auth.core.message.consumer.receiver;

import com.jugheadzhou.auth.core.message.IMessage;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;

import java.io.IOException;

/**
 * @author jugheadzhou
 * @date 2021-12-06
 */
@Slf4j
public abstract class AbstractRabbitmqReceiver {

    /**
     * 处理消息模板方法
     *
     * @param iMessage
     * @param channel
     * @param message
     */
    public void handle(IMessage iMessage, Channel channel, Message message) {
        log.info("接收到rabbitmq的内容：iMessage = {} \n message = {}", iMessage, message);
        try {
            // 处理消息内容
            handleMessage(iMessage, channel, message);
            // 处理消息后手动确认
            afterHandleMessage(channel, message);
        } catch (Exception e) {
            // 处理异常
            handleException(iMessage, channel, message, e);
        }
    }

    /**
     * 处理消息内容
     *
     * @param iMessage
     * @param channel
     * @param message
     * @throws Exception
     */
    public abstract void handleMessage(IMessage iMessage, Channel channel, Message message) throws Exception;

    /**
     * 处理完消息后手动确认
     *
     * @param channel
     * @param message
     * @throws Exception
     */
    public void afterHandleMessage(Channel channel, Message message) throws Exception {
        // 确认收到消息，false只确认当前consumer一个消息收到，true确认所有consumer获得的消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    /**
     * 处理消息异常
     *
     * @param iMessage
     * @param channel
     * @param message
     * @param e
     */
    public void handleException(IMessage iMessage, Channel channel, Message message, Exception e) {
        try {
            if (message.getMessageProperties().getRedelivered()) {
                log.info("rabbitmq消息已重复处理失败，拒绝再次接收并尝试放入死信队列中：iMessage = {}", iMessage, e);
                // 拒绝消息，requeue=false 表示不再重新入队，如果配置了死信队列则进入死信队列
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                log.info("处理rabbitmq消息失败，将再次返回队列中处理：iMessage = {}", iMessage, e);
                // multiple 是否所有消费则都响应，requeue 是否重新入队
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        } catch (IOException ex) {
            log.error("处理rabbitmq的消息发生了未知异常：", ex);
        }
    }

}
